import json
from typing import List

from re_common.baselibrary.utils.core.mdeprecated import try_except2_async

from apps.crawler_platform.core_callback import *
from apps.crawler_platform.core_callback.err_callback import all_client_back_callback
from apps.crawler_platform.core_platform.base_core import BaseCoreStep
from apps.crawler_platform.core_platform.core_down import CoreDownMixin
from apps.crawler_platform.core_platform.core_sql import CoreSqlMixin
from apps.crawler_platform.core_platform.g_model import CallBackModel, DealModel, DealItemModel, DealInsertModel, \
    DealUpdateModel, DealItemNextModel

STATICA_HACK = False
# globals()['kcah_acitats'[::-1].upper()] = False
if STATICA_HACK:  # pragma: no cover
    null()


class BaseDown(BaseCoreStep, CoreDownMixin):
    """
    下载分支的基础类
    """

    def __init__(self):
        super().__init__()

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def down(self):
        if self.pm.turn_page in [2, 1]:
            # 翻页下载，不管失败与否，翻页到最后，返回的状态由最后一个下载决定
            return await self.page_down()
        elif self.pm.turn_page == 3:
            # 该模式下 下载失败且有明确的code时会返回true，表示继续下载
            return await self.stat_down()
        elif self.pm.turn_page == 0:
            # 该下载模式下，会按顺序下载，某个keys下载失败会返回错误,且下次重新下载
            # 会全部下载，不会跳过(当然这里是指taskinfo 的多条配置之间的逻辑，单条
            # 翻页逻辑的跳过不归这里管)
            return await self.order_down()
        elif self.pm.turn_page == 4:
            return await self.deal_down()
        elif self.pm.turn_page in [5, 6]:
            return await self.multiple_page_down()
        elif self.pm.turn_page in [7, 8]:  # 每页分开下载
            return await self.part_page_down()
        elif self.pm.turn_page in [9, 10]:
            return await self.list_multiple_page_down()
        else:
            raise Exception("异常 没有这种下载模式")

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def deal_html(self, TModel):
        self.step_info = self.add_all_process_info(f"处理解析，通过配置css和xpath进行解析")
        bools, err_info = await self.para_next()
        if not bools:
            return bools, err_info
        callmodel = CallBackModel[TModel](
            para_dicts=self.para_dicts,
            sql_model=self.pm.sql_model,
            redis_all=self.redis_model
        )
        self.deal_model: DealModel = self.callback_deal_html(callmodel)
        return True, {}

    def callback_deal_html(self, callmodel) -> DealModel:
        name = "_".join([self.pm.task_name, self.pm.task_tag, "callback"])
        # print(name)
        callback = eval(name)
        return callback(callmodel)

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def save_sql(self, table, next_table, type="", msg=""):
        if type != "":
            return await super().save_sql(table, next_table, type=type, msg=msg)


        # 标准化处理数据库流程
        # befor 操作
        befor_deal_item_model: DealItemModel = self.deal_model.befor_dicts
        insert_list: List[DealInsertModel] = befor_deal_item_model.insert
        for insert in insert_list:
            lists: List[dict] = insert.lists
            insert_pre: str = insert.insert_pre
            if lists:
                list_v = []
                list_key = list(lists[0].keys())
                for item in lists:
                    list_v.append(tuple(item.values()))
                bools, dicts = await CoreSqlMixin.insert_many_sql(
                    table, list_key, list_v,
                    insert=insert_pre)

                if not bools:
                    return bools, dicts

        update_list: List[DealUpdateModel] = befor_deal_item_model.update_list
        list_para = list()
        for update_item in update_list:
            update_no_placeholder: dict = update_item.update_no_placeholder
            update = update_item.update
            where = update_item.where
            list_para.append((table, update, update_no_placeholder, where))

        bools, dicts = await CoreSqlMixin.update_list_sql(list_para)
        if not bools:
            return bools, dicts



        # next操作
        next_deal_item_model: DealItemNextModel = self.deal_model.next_dicts
        insert_list: List[DealInsertModel] = next_deal_item_model.insert
        for insert in insert_list:
            lists: List[dict] = insert.lists
            insert_pre: str = insert.insert_pre
            if lists:
                list_v = []
                list_key = list(lists[0].keys())
                for item in lists:
                    list_v.append(tuple(item.values()))
                bools, dicts = await CoreSqlMixin.insert_many_sql(
                    next_table, list_key, list_v,
                    insert=insert_pre)
                if not bools:
                    return bools, dicts

        update_list: List[DealUpdateModel] = next_deal_item_model.update_list
        list_para_next = list()
        for update_item in update_list:
            update_no_placeholder: dict = update_item.update_no_placeholder
            update = update_item.update
            where = update_item.where
            list_para_next.append((next_table, update, update_no_placeholder, where))
        bools, dicts = await CoreSqlMixin.update_list_sql(list_para_next)
        if not bools:
            return bools, dicts

        # 更新和 other_dicts 和 null_dicts 的更新放在一起，这段代码是befor的数据,放在一起更新，节约更新次数
        other_dicts = self.deal_model.other_dicts
        null_dicts = self.deal_model.null_dicts
        vv = {}
        #############################################
        # 更新状态
        # CoreSqlMixin.set_state(self.pm)
        # where = self.pm.get_pkm()
        # vv.update(self.pm.get_sql_state())
        # self.pm.set_sql_state(vv)

        self.statemanager.set_state(self.pm)
        where = self.pm.get_pkm()
        vv.update(self.pm.get_sql_state())
        # 这个位置是防止self.pm.get_sql_state()里有json数据，防止被覆盖
        vv.update(befor_deal_item_model.update)
        vv.update({"other_dicts": json.dumps(other_dicts, ensure_ascii=False)})
        vv.update({"null_dicts": json.dumps(null_dicts, ensure_ascii=False)})
        # self.statemanager.debug_dicts(self.pm)
        self.pm.set_sql_state(vv)
        #####################
        update_no_placeholder: dict = self.pm.get_update_no_placeholder()
        update_no_placeholder.update(befor_deal_item_model.update_no_placeholder)
        if vv or update_no_placeholder:
            bools, dicts = await CoreSqlMixin.update_sql(table, vv, update_no_placeholder, where)
            return bools, dicts
        else:
            return True, {"msg": "没有执行最后的更新sql"}
